package com.personal.system.service.impl;

import cn.hutool.core.lang.UUID;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.personal.model.system.SysUser;
import com.personal.system.entity.seckill.Goods;
import com.personal.system.entity.seckill.OrderInfo;
import com.personal.system.entity.seckill.SeckillGoods;
import com.personal.system.entity.seckill.SeckillOrder;
import com.personal.system.mapper.seckill.OrderInfoMapper;
import com.personal.system.mapper.seckill.SeckillGoodsMapper;
import com.personal.system.mapper.seckill.SeckillOrderMapper;
import com.personal.system.service.SeckillService;
import com.personal.system.config.SecurityUtil;
import com.personal.system.constant.redis.RedisService;
import com.personal.system.constant.redis.SeckillKey;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.Date;

@Slf4j
@Service
public class SeckillServiceImpl extends ServiceImpl<SeckillGoodsMapper,SeckillGoods> implements SeckillService {

    @Resource
    private SeckillGoodsMapper seckillGoodsMapper;

    @Resource
    private SecurityUtil securityUtil;

    @Resource
    private RedisService redisService;

    @Resource
    private SeckillOrderMapper orderMapper;

    @Resource
    private OrderInfoMapper infoMapper;

    @Override
    public Object getSeckillGoodsList(Page<Goods> page) {
        if (null == page){
            return seckillGoodsMapper.selectAllGoods();
        }
        return seckillGoodsMapper.selectAllGoods(page);
    }

    @Override
    public IPage<SeckillGoods> selectPage(Page<SeckillGoods> pageParam) {

        return seckillGoodsMapper.selectSecGoods(pageParam,null);
    }

    @Override
    public SeckillGoods getById(Long id) {
        SeckillGoods goods = seckillGoodsMapper.getById(id);
        if (goods != null){
            long startAt = goods.getStartDate().getTime();
            long endAt = goods.getEndDate().getTime();
            long now = System.currentTimeMillis();

            int remainSeconds = 0;
            if(now < startAt ) {//秒杀还没开始，倒计时
                remainSeconds = (int)((startAt - now )/1000);
            }else  if(now > endAt){//秒杀已经结束
                remainSeconds = -1;
            }
            goods.setRemainSeconds(remainSeconds);
        }
        return goods;
    }

    @Override
    public Object getPath(Long goodsId) {
        Long userId = securityUtil.getUserId();
        if (null == userId || null == goodsId) return null;
        String str = DigestUtil.md5Hex(UUID.fastUUID().toString(true)+"123456");
        redisService.set(SeckillKey.getSeckillPath, "" + userId + "_" + goodsId, str, 60);
        return str;
    }

    @Override
    public boolean checkPath(long goodsId, String path) {
        Long userId = securityUtil.getUserId();
        if (null == userId || null == path) return false;
        String pathOld = redisService.get(SeckillKey.getSeckillPath, "" + userId + "_" + goodsId, String.class);
        return path.equals(pathOld);
    }

    @Override
    public SeckillOrder getOrderByUserNameGoodsId(String userId,long goodsId) {
        if (null == userId){
            userId = securityUtil.getUserId().toString();
        }

        SeckillOrder order = orderMapper.selectOne(Wrappers.lambdaQuery(SeckillOrder.class)
                .eq(SeckillOrder::getUserId, userId).eq(SeckillOrder::getGoodsId, goodsId));

        return order;
    }

    @Transactional
    public OrderInfo insert(SysUser user, SeckillGoods goods) {
        //秒杀商品库存减一
        LambdaUpdateWrapper<SeckillGoods> qw = new LambdaUpdateWrapper<>();
        qw.eq(SeckillGoods::getId,goods.getId());
        qw.set(SeckillGoods::getStockCount,goods.getStockCount()-1);

        int success = seckillGoodsMapper.update(null, qw);
        if (success == 1){
            OrderInfo orderInfo = new OrderInfo();
            orderInfo.setCreateDate(new Date());
            orderInfo.setAddrId(0L);
            orderInfo.setGoodsCount(1);
            orderInfo.setGoodsId(goods.getId());
            orderInfo.setGoodsName(goods.getGoodsName());
            orderInfo.setGoodsPrice(goods.getSeckilPrice());
            orderInfo.setOrderChannel(1);
            orderInfo.setStatus(0);
            orderInfo.setUserId(Long.valueOf(user.getId()));
            infoMapper.insert(orderInfo);
            log.info("插入的订单信息ID》》" + orderInfo.getId());

            SeckillOrder seckillOrder = new SeckillOrder();
            seckillOrder.setOrderId(orderInfo.getId());
            seckillOrder.setGoodsId(goods.getId());
            seckillOrder.setUserId(Long.valueOf(user.getId()));
            orderMapper.insert(seckillOrder);

            return orderInfo;
        }else {
            setGoodsOver(goods.getId());
            return null;
        }
    }

    @Override
    public long getMiaoResult(long goodsId) {
        SeckillOrder seckillOrder = this.getOrderByUserNameGoodsId(null,goodsId);
        if (null != seckillOrder){
            return seckillOrder.getOrderId();
        } else {
            boolean isOver = this.getGoodsOver(goodsId);
            if (isOver){
                return -1;
            } else {
                return 0;
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public int updateGoods(SeckillGoods goods) {
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        int cou = 0;
        if (goods.getId() != null && goods.getGoodsId() != null){
            LambdaUpdateWrapper<SeckillGoods> uw = new LambdaUpdateWrapper<>();
            uw.eq(SeckillGoods::getId, goods.getId());
            uw.set(SeckillGoods::getSeckilPrice,goods.getSeckilPrice());
            uw.set(SeckillGoods::getStartDate,goods.getStartDate());
            uw.set(SeckillGoods::getEndDate,goods.getEndDate());

            this.update(uw);
            cou += seckillGoodsMapper.updateGoods(goods);
        }
        return cou;
    }

    //秒杀商品结束标记
    private void setGoodsOver(Long goodsId) {
        redisService.set(SeckillKey.isGoodsOver, "" + goodsId, true, 60);
    }

    //查看秒杀商品是否已经结束
    private boolean getGoodsOver(long goodsId) {
        return redisService.exists(SeckillKey.isGoodsOver, "" + goodsId);
    }

}
